package com.openbravo.pos.sales;

import java.awt.Component;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import javax.print.PrintService;
import javax.swing.JComponent;
import javax.swing.JPanel;

import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRMapArrayDataSource;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.xml.JRXmlLoader;

import cn.ekuma.data.dao.ListKeyed;
import cn.ekuma.data.ui.swing.JEditorWarpDialog;
import cn.ekuma.epos.bean.util.PaymentInfoHelper;
import cn.ekuma.epos.bean.util.sale.TicketHelper;
import cn.ekuma.epos.bean.util.sale.TicketLineHelper;
import cn.ekuma.epos.bean.util.sale.TicketLineWarp;
import cn.ekuma.epos.bean.util.sale.TicketWarp;
import cn.ekuma.epos.businesslogic.RoleUtil;
import cn.ekuma.epos.businesslogic.TicketUtil;
import cn.ekuma.epos.core.util.ProductSwingUtil;
import cn.ekuma.epos.datalogic.I_DataLogicCustomers;
import cn.ekuma.epos.datalogic.I_DataLogicReceipts;
import cn.ekuma.epos.datalogic.I_DataLogicSales;
import cn.ekuma.epos.datalogic.I_DataLogicSystem;
import cn.ekuma.epos.datalogic.define.DataLogicSystemHelper;
import cn.ekuma.epos.servings.JServingsEditorDialog;
import cn.ekuma.rabbit.spi.I_ModelPart;
import cn.ekuma.security.I_SecurityManager;

import com.openbravo.bean.AppUser;
import com.openbravo.bean.Customer;
import com.openbravo.bean.PaymentInfo;
import com.openbravo.bean.PaymentInfoCash;
import com.openbravo.bean.Product;
import com.openbravo.bean.ProductScore;
import com.openbravo.bean.Serving;
import com.openbravo.bean.Tax;
import com.openbravo.bean.TaxCategory;
import com.openbravo.bean.infobean.CustomerInfo;
import com.openbravo.bean.sales.Ticket;
import com.openbravo.bean.sales.TicketLine;
import com.openbravo.data.basic.BasicException;
import com.openbravo.data.gui.ComboBoxValModel;
import com.openbravo.data.gui.JMessageDialog;
import com.openbravo.data.gui.MessageInf;
import com.openbravo.data.user.DirtyManager;
import com.openbravo.pos.base.AppLocal;
import com.openbravo.pos.base.AppView;
import com.openbravo.pos.base.BeanFactoryApp;
import com.openbravo.pos.base.BeanFactoryException;
import com.openbravo.pos.base.I_AppView;
import com.openbravo.pos.base.I_ScriptCommand;
import com.openbravo.pos.base.ScriptArg;
import com.openbravo.pos.customers.CustomersEditor;
import com.openbravo.pos.forms.JPanelView;
import com.openbravo.pos.forms.JRootApp;
import com.openbravo.pos.mode.POS_UI_Swing_Model;
import com.openbravo.pos.panels.JCustomerFinder;
import com.openbravo.pos.panels.JPanelButtons;
import com.openbravo.pos.panels.JProductAttEdit;
import com.openbravo.pos.panels.JProductDetail;
import com.openbravo.pos.panels.JProductFinder;
import com.openbravo.pos.payment.JPaymentSelect;
import com.openbravo.pos.printer.AbstractTicketPrintManager;
import com.openbravo.pos.printer.TicketParser;
import com.openbravo.pos.printer.TicketPrinterException;
import com.openbravo.pos.sales.event.TicketEvent;
import com.openbravo.pos.sales.event.TicketLineEvent;
import com.openbravo.pos.scale.ScaleException;
import com.openbravo.pos.scripting.ScriptEngine;
import com.openbravo.pos.scripting.ScriptException;
import com.openbravo.pos.scripting.ScriptFactory;
import com.openbravo.pos.util.JRPrinterAWT300;
import com.openbravo.pos.util.ReportUtils;

public abstract class AbstractJPanelTicket extends JPanel implements JPanelView, BeanFactoryApp, TicketsEditor,I_ScriptCommand ,I_ModelPart<POS_UI_Swing_Model>{
	

	protected static final int NUMBERZERO = 0;
	protected static final int NUMBERVALID = 1;
	protected static final int NUMBER_INPUTZERO = 0;
	private static final int NUMBER_INPUTZERODEC = 1;
	private static final int NUMBER_INPUTINT = 2;
	private static final int NUMBER_INPUTDEC = 3;
	private static final int NUMBER_PORZERO = 4;
	private static final int NUMBER_PORZERODEC = 5;
	private static final int NUMBER_PORINT = 6;
	private static final int NUMBER_PORDEC = 7;
	protected JTicketLines m_ticketlines;
	protected TicketParser m_TTP;
	protected Ticket m_oTicket;
	protected Object m_oTicketExt;
	protected int m_iNumberStatus;
	protected int m_iNumberStatusInput;
	protected int m_iNumberStatusPor;
	protected StringBuffer m_sBarcode;
	protected JTicketsBag m_ticketsbag;
	protected ListKeyed taxcollection;
	protected ComboBoxValModel taxcategoriesmodel;
	protected TaxesLogic taxeslogic;
	protected JPanelButtons m_jbtnconfig;
	protected JRootApp m_App;
	protected I_DataLogicSystem dlSystem;
	protected I_DataLogicSales dlSales;
	protected I_DataLogicCustomers dlCustomers;
	protected I_DataLogicReceipts dlReceipts;
	protected JPaymentSelect paymentdialogreceipt;
	protected JPaymentSelect paymentdialogrefund;
	private JEditorWarpDialog productCreateDialog;
	private JEditorWarpDialog customerCreateDialog;
	protected String cashChanged;
	protected AbstractTicketPrintManager printManager;
	protected boolean quickSellAble;
	protected String cashPaid;
	protected String priceGroup;
	boolean isEditAble=false;
	protected boolean isCheckProductLocation;
	protected I_SecurityManager security;

	public void init(I_AppView app) throws BeanFactoryException {
		m_App = (JRootApp) app;
		
		m_TTP = new TicketParser(m_App.getDeviceTicket(), dlSystem);
	}
	
	
	public boolean deactivate() {
		return m_ticketsbag.deactivate();
	}
	
	@Override
	public Object getBean() {
		return this;
	}

	@Override
	public JComponent getComponent() {
		return this;
	}

	protected abstract JTicketsBag getJTicketsBag();

	protected abstract Component getSouthComponent();

	protected abstract void resetSouthComponent();
	
	protected abstract void stateToZero();
	
	protected abstract void printPartialTotals();
	
	protected abstract void refreshTicketLineSelectedState();
	
	protected abstract void refreshTicket();

	
	public void setActiveTicket(Ticket oTicket, Object oTicketExt,boolean isEditAble) {
	
		m_oTicket = oTicket;
		m_oTicketExt = oTicketExt;
		this.isEditAble=isEditAble;
		if (m_oTicket != null&&isEditAble) {
			// Asign preeliminary properties to the receipt
			m_oTicket.setUser(m_App.getAppUserView().getUser().getUserInfo());
			m_oTicket.setActiveCash(m_App.getUserCashIndex());
			m_oTicket.setDate(new Date()); // Set the edition date.
		}
	
		executeEvent(m_oTicket, m_oTicketExt, "ticket.show");
	
		refreshTicket();
	}

	
	
	
	@Override
	public Ticket getActiveTicket() {
		return m_oTicket;
	}


	private void paintTicketLine(int index, TicketLine oLine) {
	
		if (executeEventAndRefresh("ticket.setline", new ScriptArg("index",
				index), new ScriptArg("line", oLine)) == null) {
	
			TicketLine oldLine = m_oTicket.getLine(index);
	
			m_oTicket.setLine(index, oLine);
			m_ticketlines.setTicketLine(index, oLine);
			m_ticketlines.setSelectedIndex(index);
			try {
				for (I_TicketLinePrintListener l : listenerList
						.getListeners(I_TicketLinePrintListener.class))
					l.fireTicketLineChanged(new TicketLineEvent(oldLine, oLine));
			} catch (ScriptException e) {
				MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
						AppLocal.getIntString("message.cannotprintticket"), e);
				msg.show(AbstractJPanelTicket.this);
			} catch (TicketPrinterException e) {
				MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
						AppLocal.getIntString("message.cannotprintticket"), e);
				msg.show(AbstractJPanelTicket.this);
			}
			visorTicketLine(oLine); // Y al visor tambien...
			printPartialTotals();
			stateToZero();
	
			// event receipt
			executeEventAndRefresh("ticket.change");
		}
	}

	private void addTicketLine(Product oProduct, double dMul, double dPrice) {
	
		Tax tax = taxeslogic.getTaxInfo(oProduct.getTaxCategoryID(),
				m_oTicket.getCustomer());
	
		addTicketLine(new TicketLine(oProduct, dMul, dPrice, tax,
				(java.util.HashMap) (oProduct.getProperties().clone()),
				m_oTicket.getM_dPriceRate()));
	}

	protected void addTicketLine(TicketLine oLine) {
	
		if (executeEventAndRefresh("ticket.addline", new ScriptArg("line",
				oLine)) == null) {
	
			if (oLine.isProductCom()) {
				// Comentario entonces donde se pueda
				int i = m_ticketlines.getSelectedIndex();
	
				// me salto el primer producto normal...
				if (i >= 0 && !m_oTicket.getLine(i).isProductCom()) {
					i++;
				}
	
				// me salto todos los productos auxiliares...
				while (i >= 0 && i < m_oTicket.getLinesCount()
						&& m_oTicket.getLine(i).isProductCom()) {
					i++;
				}
	
				if (i >= 0) {
					TicketLine newAddLine;
					try {
						newAddLine = TicketUtil.insertLine(dlSales, m_oTicket,
								i, oLine,m_App.getDefineLocation());
						TicketUtil.checkTicketLineProductScore(dlSales, m_oTicket, oLine, ProductScore.TYPE_Store,m_App.getDefineLocation());
						m_ticketlines.insertTicketLine(i, oLine); // Pintamos la
						// linea en la
						// vista...
						if (newAddLine != null) {
							m_ticketlines.insertTicketLine(i + 1, newAddLine);
						}
					} catch (BasicException e) {
						new MessageInf(e).show(AbstractJPanelTicket.this);
					}

				} else {
					Toolkit.getDefaultToolkit().beep();
				}
			} else {
				// Producto normal, entonces al finalnewline.getMultiply()
				TicketLine newAddLine=null;
				try {
					newAddLine = TicketUtil.addLine(dlSales, m_oTicket,
							oLine,m_App.getDefineLocation());
					TicketUtil.checkTicketLineProductScore(dlSales, m_oTicket, oLine, ProductScore.TYPE_Store,m_App.getDefineLocation());
					m_ticketlines.addTicketLine(oLine); // Pintamos la linea en la
					// vista...
					
				} catch (BasicException e1) {
					new MessageInf(e1).show(AbstractJPanelTicket.this);
					return;
				}
				try {
					for (I_TicketLinePrintListener l : listenerList
							.getListeners(I_TicketLinePrintListener.class))
						l.fireTicketLineAdded(new TicketLineEvent(oLine));
				} catch (ScriptException e) {
					MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
							AppLocal.getIntString("message.cannotprintticket"),
							e);
					msg.show(AbstractJPanelTicket.this);
				} catch (TicketPrinterException e) {
					MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
							AppLocal.getIntString("message.cannotprintticket"),
							e);
					msg.show(AbstractJPanelTicket.this);
				}
				if (newAddLine != null) {
					Tax tax = taxeslogic.getTaxInfo(
							newAddLine.getProductTaxCategoryID(),
							m_oTicket.getCustomer());
					newAddLine.setTaxInfo(tax);
					m_ticketlines.addTicketLine(newAddLine);
					try {
						for (I_TicketLinePrintListener l : listenerList
								.getListeners(I_TicketLinePrintListener.class))
							l.fireTicketLineAdded(new TicketLineEvent(
									newAddLine));
					} catch (ScriptException e) {
						MessageInf msg = new MessageInf(
								MessageInf.SGN_WARNING,
								AppLocal.getIntString("message.cannotprintticket"),
								e);
						msg.show(AbstractJPanelTicket.this);
					} catch (TicketPrinterException e) {
						MessageInf msg = new MessageInf(
								MessageInf.SGN_WARNING,
								AppLocal.getIntString("message.cannotprintticket"),
								e);
						msg.show(AbstractJPanelTicket.this);
					}
				}
			}
	
			visorTicketLine(oLine);
			printPartialTotals();
			stateToZero();
	
			// event receipt
			executeEventAndRefresh("ticket.change");
		}
	}

	private void removeTicketLine(int i) {
		if (!RoleUtil.hasPermission(AbstractJPanelTicket.this, (AppUser) m_App
				.getAppUserView().getUser(), dlSystem,
				RoleUtil.Permission_EDIT_TICKET_LINE))
			return;
		if (executeEventAndRefresh("ticket.removeline", new ScriptArg("index",
				i)) == null) {
	
			if (m_oTicket.getLine(i).isProductCom()) {
				// Es un producto auxiliar, lo borro y santas pascuas.
				m_oTicket.removeLine(i);
				m_ticketlines.removeTicketLine(i);
			} else {
				TicketLine removeLine = m_oTicket.getLine(i);
	
				// Es un producto normal, lo borro.
				m_oTicket.removeLine(i);
				m_ticketlines.removeTicketLine(i);
				try {
					for (I_TicketLinePrintListener l : listenerList
							.getListeners(I_TicketLinePrintListener.class))
						l.fireTicketLineDeleted(new TicketLineEvent(removeLine));
				} catch (ScriptException e) {
					MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
							AppLocal.getIntString("message.cannotprintticket"),
							e);
					msg.show(AbstractJPanelTicket.this);
				} catch (TicketPrinterException e) {
					MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
							AppLocal.getIntString("message.cannotprintticket"),
							e);
					msg.show(AbstractJPanelTicket.this);
				}
				// Y todos lo auxiliaries que hubiera debajo.
				while (i < m_oTicket.getLinesCount()
						&& m_oTicket.getLine(i).isProductCom()) {
					m_oTicket.removeLine(i);
					m_ticketlines.removeTicketLine(i);
				}
			}
	
			visorTicketLine(null); // borro el visor
			printPartialTotals(); // pinto los totales parciales...
			stateToZero(); // Pongo a cero
	
			// event receipt
			executeEventAndRefresh("ticket.change");
		}
	}

	@Override
	public ListKeyed getTaxCollection() {
		return taxcollection;
	}

	@Override
	public TaxesLogic getTaxLogic() {
		return taxeslogic;
	}

	@Override
	public Object getTicketExt() {
		return m_oTicketExt;
	}


	private Product getInputProduct() {
		Product oProduct = new Product(); // Es un ticket
		oProduct.setReference(null);
		oProduct.setCode(null);
		oProduct.setName("");
		oProduct.setTaxCategoryID(((TaxCategory) taxcategoriesmodel
				.getSelectedItem()).getID());
	
		oProduct.setPriceSell(includeTaxes(oProduct.getTaxCategoryID(),
				getInputValue()));
	
		return oProduct;
	}

	private double includeTaxes(String tcid, double dValue) {
		if (m_jaddtax.isSelected()) {
			Tax tax = taxeslogic.getTaxInfo(tcid, m_oTicket.getCustomer());
			double dTaxRate = tax == null ? 0.0 : tax.getRate();
			return dValue / (1.0 + dTaxRate);
		} else {
			return dValue;
		}
	}

	protected double getInputValue() {
		try {
			return Double.parseDouble(m_jPrice.getText());
		} catch (NumberFormatException e) {
			return 0.0;
		}
	}

	private double getPorValue() {
		try {
			return Double.parseDouble(m_jPor.getText().substring(1));
		} catch (NumberFormatException e) {
			return 1.0;
		} catch (StringIndexOutOfBoundsException e) {
			return 1.0;
		}
	}

	private void incProductByCode(String sCode) {
		if(sCode.isEmpty()){
	           stateToZero();
	           return ;
	        }
	        boolean isSeachModel=false;
	        // precondicion: sCode != null
	        sCode.toUpperCase();
	        try {
	            Product oProduct=null;
	            if(quickSellAble&&sCode.startsWith("~")){
	            	isSeachModel=true;
	                  java.util.List<Product> prods=dlSales.listProductByMnemonic(sCode.substring(1));
	                  if(prods!=null&&prods.size()>0)
	                      if(prods.size()==1)
	                         oProduct=prods.get(0);
	                      else
	                         oProduct=getProductFinder().setProductList(prods);
	            }else{
	            	oProduct = ProductSwingUtil.getProductInfo(this, dlSales,  sCode.trim());
	            }
	            if (oProduct == null) {                  
	                Toolkit.getDefaultToolkit().beep(); 
	                stateToZero();
	                new MessageInf(MessageInf.SGN_WARNING, AppLocal.getIntString("message.noproduct")).show(this);
	            } else {
	                // Se anade directamente una unidad con el precio y todo
	                incProduct(oProduct);
	            }
	        } catch (BasicException eData) {
	            stateToZero();           
	            new MessageInf(eData).show(this);           
	        }
	}

	private void incProductByCodePrice(String sCode, double dPriceSell) {
		// precondicion: sCode != null
			Product oProduct  = ProductSwingUtil.getProductInfo(this, dlSales, sCode);
			if (oProduct == null) {
				Toolkit.getDefaultToolkit().beep();
				new MessageInf(MessageInf.SGN_WARNING,
						AppLocal.getIntString("message.noproduct")).show(this);
				stateToZero();
			} else {
				// Se anade directamente una unidad con el precio y todo
				if (m_jaddtax.isSelected()) {
					// debemos quitarle los impuestos ya que el precio es con
					// iva incluido...
					Tax tax = taxeslogic.getTaxInfo(
							oProduct.getTaxCategoryID(),
							m_oTicket.getCustomer());
					addTicketLine(oProduct, 1.0,
							dPriceSell / (1.0 + tax.getRate()));
				} else {
					addTicketLine(oProduct, 1.0, dPriceSell);
				}
			}
	}

	protected void incProduct(Product prod) {
	    try {
			if(prod.getID()!=null&&!dlSales.isProductOutAble(m_App.getInventoryLocation(), prod.getID())){
				Toolkit.getDefaultToolkit().beep();
				new MessageInf(MessageInf.SGN_WARNING,
						AppLocal.getIntString("message.productNoOutAble"))
						.show(this);
				stateToZero();
				return;
			}
			if(prod.getID()!=null&&isCheckProductLocation&&!dlSales.isProductStoreEnough(m_App.getInventoryLocation(), prod.getID(),1)){
				new MessageInf(MessageInf.SGN_WARNING,AppLocal.getIntString("message.productNoStoreEnough")).show(this);
				return;
			}
		} catch (BasicException e1) {
			new MessageInf(MessageInf.SGN_WARNING,e1.getMessage()).show(this);
			return;
		}
	    	
		if (prod.isScale() && m_App.getDeviceScale().existsScale()) {
			try {
				Double value = m_App.getDeviceScale().readWeight();
				if (value != null) {
					incProduct(value.doubleValue(), prod);
				}
			} catch (ScaleException e) {
				Toolkit.getDefaultToolkit().beep();
				new MessageInf(MessageInf.SGN_WARNING,
						AppLocal.getIntString("message.noweight"), e)
						.show(this);
				stateToZero();
			}
		} else {
			// No es un producto que se pese o no hay balanza
			incProduct(1.0, prod);
		}
	}

	protected void incProduct(double dPor, Product prod) {
		// precondicion: prod != null
		Customer customer = m_oTicket.getCustomer();
		double salePrice = prod.getPriceSell();
		if (customer != null && prod.getM_dCustomerPrice() > 0) {
			salePrice = prod.getM_dCustomerPrice();
		}
		if(priceGroup!=null){
			try {
                salePrice=TicketUtil.getProductPrice(dlSales,customer,prod,priceGroup); 
			} catch (BasicException e) {
				Toolkit.getDefaultToolkit().beep();
				new MessageInf(e).show(this);
				return;
			}
		}
		 addTicketLine(prod, dPor, salePrice);
	}

	protected void buttonTransition(Product prod) {
		// precondicion: prod != null
	
		if (m_iNumberStatusInput == NUMBERZERO
				&& m_iNumberStatusPor == NUMBERZERO) {
			incProduct(prod);
		} else if (m_iNumberStatusInput == NUMBERVALID
				&& m_iNumberStatusPor == NUMBERZERO) {
			incProduct(getInputValue(), prod);
		} else {
			Toolkit.getDefaultToolkit().beep();
		}
	}

	private void stateTransition(char cTrans) {

	    if(!isEditAble){
	    	stateToZero();
	    	if(cTrans == '+'){
	    		m_ticketsbag.showNextTicket();
	    	}else if(cTrans == '-'){
	    		m_ticketsbag.showPrevTicket();
	    	}else
	    	    m_ticketsbag.selectValidTicket();
            return;
	    }
		if (cTrans == '\n') {
			// Codigo de barras introducido
			if (m_sBarcode.length() > 0) {
				String sCode = m_sBarcode.toString();
				if (sCode.startsWith("c")) {
					// barcode of a customers card
					try {
						Customer newcustomer = dlSales.findCustomerByCard(sCode);
						if (newcustomer == null)
							newcustomer = dlSales.findCustomerByStoreCard(sCode.substring(1));
						if (newcustomer == null) {
							Toolkit.getDefaultToolkit().beep();
							new MessageInf(MessageInf.SGN_WARNING,
									AppLocal.getIntString("message.nocustomer"))
									.show(this);
						} else {
							TicketUtil.changeCustomer(dlSales, m_oTicket,
									newcustomer,priceGroup);
							m_oTicket.setCustomer(newcustomer);
							m_jTicketId.setText(TicketHelper.getName(m_oTicket,
									m_oTicketExt));
						}
					} catch (BasicException e) {
						Toolkit.getDefaultToolkit().beep();
						new MessageInf(MessageInf.SGN_WARNING,
								AppLocal.getIntString("message.nocustomer"), e)
								.show(this);
					}
					stateToZero();
				} else if (sCode.length() == 13 && sCode.startsWith("250")) {
					// barcode of the other machine
					Product oProduct = new Product(); // Es un ticket
					oProduct.setReference(null); // para que no se grabe
					oProduct.setCode(sCode);
					oProduct.setName("Ticket " + sCode.substring(3, 7));
					oProduct.setPriceSell(Double.parseDouble(sCode.substring(7,
							12)) / 100);
					oProduct.setTaxCategoryID(((TaxCategory) taxcategoriesmodel
							.getSelectedItem()).getID());
					// Se anade directamente una unidad con el precio y todo
					addTicketLine(
							oProduct,
							1.0,
							includeTaxes(oProduct.getTaxCategoryID(),
									oProduct.getPriceSell()));
				} else if (sCode.length() == 13 && sCode.startsWith("210")) {
					// barcode of a weigth product
					incProductByCodePrice(sCode.substring(0, 7),
							Double.parseDouble(sCode.substring(7, 12)) / 100);
				} else {
					incProductByCode(sCode);
				}
			} else {
				Toolkit.getDefaultToolkit().beep();
			}
		} else {
			// otro caracter
			// Esto es para el codigo de barras...
			m_sBarcode.append(cTrans);
	
			// Esto es para el los productos normales...
			if (cTrans == '\u007f') {
				stateToZero();
	
			}else if (quickSellAble&&(cTrans == '~'||cTrans == '～')&& (m_iNumberStatus == NUMBER_INPUTZERO)) {
                m_jPrice.setText("~");
                m_iNumberStatus = NUMBER_INPUTINT;    
                m_iNumberStatusInput = NUMBERVALID;
           }else if(String.valueOf(cTrans).matches("[A-Z|a-z]")&&m_iNumberStatus == NUMBER_INPUTZERO&&cTrans!='c'){
        	   quickSaleByKeyStoke(cTrans);
           }/**else if ((cTrans == '0')  && (m_iNumberStatus == NUMBER_INPUTZERO)) {
               m_jPrice.setText("0");            
           }**/ else if ((cTrans == '0' || cTrans == '1' || cTrans == '2' || cTrans == '3'
					|| cTrans == '4' || cTrans == '5' || cTrans == '6'
					|| cTrans == '7' || cTrans == '8' || cTrans == '9')
					&& (m_iNumberStatus == NUMBER_INPUTZERO)) {
				// Un numero entero
				m_jPrice.setText(Character.toString(cTrans));
				m_iNumberStatus = NUMBER_INPUTINT;
				m_iNumberStatusInput = NUMBERVALID;
			} else if ((cTrans == '0' || cTrans == '1' || cTrans == '2'
					|| cTrans == '3' || cTrans == '4' || cTrans == '5'
					|| cTrans == '6' || cTrans == '7' || cTrans == '8' || cTrans == '9')
					&& (m_iNumberStatus == NUMBER_INPUTINT)) {
				// Un numero entero
				m_jPrice.setText(m_jPrice.getText() + cTrans);
	
			}else if(quickSellAble&&String.valueOf(cTrans).matches("[A-Z|a-z]")&&(m_iNumberStatus == NUMBER_INPUTZERO || m_iNumberStatus == NUMBER_INPUTINT)){
            	m_jPrice.setText(m_jPrice.getText() + cTrans);
            } else if (cTrans == '.' && m_iNumberStatus == NUMBER_INPUTZERO) {
				m_jPrice.setText("0.");
				m_iNumberStatus = NUMBER_INPUTZERODEC;
			} else if (cTrans == '.' && m_iNumberStatus == NUMBER_INPUTINT) {
				m_jPrice.setText(m_jPrice.getText() + ".");
				m_iNumberStatus = NUMBER_INPUTDEC;
	
			} else if ((cTrans == '0')
					&& (m_iNumberStatus == NUMBER_INPUTZERODEC || m_iNumberStatus == NUMBER_INPUTDEC)) {
				// Un numero decimal
				m_jPrice.setText(m_jPrice.getText() + cTrans);
			} else if ((cTrans == '1' || cTrans == '2' || cTrans == '3'
					|| cTrans == '4' || cTrans == '5' || cTrans == '6'
					|| cTrans == '7' || cTrans == '8' || cTrans == '9')
					&& (m_iNumberStatus == NUMBER_INPUTZERODEC || m_iNumberStatus == NUMBER_INPUTDEC)) {
				// Un numero decimal
				m_jPrice.setText(m_jPrice.getText() + cTrans);
				m_iNumberStatus = NUMBER_INPUTDEC;
				m_iNumberStatusInput = NUMBERVALID;
	
			} else if (cTrans == '*'
					&& (m_iNumberStatus == NUMBER_INPUTINT || m_iNumberStatus == NUMBER_INPUTDEC)) {
				m_jPor.setText("x");
				m_iNumberStatus = NUMBER_PORZERO;
			} else if (cTrans == '*'
					&& (m_iNumberStatus == NUMBER_INPUTZERO || m_iNumberStatus == NUMBER_INPUTZERODEC)) {
				m_jPrice.setText("0");
				m_jPor.setText("x");
				m_iNumberStatus = NUMBER_PORZERO;
	
			} else if ((cTrans == '0') && (m_iNumberStatus == NUMBER_PORZERO)) {
				m_jPor.setText("x0");
			} else if ((cTrans == '1' || cTrans == '2' || cTrans == '3'
					|| cTrans == '4' || cTrans == '5' || cTrans == '6'
					|| cTrans == '7' || cTrans == '8' || cTrans == '9')
					&& (m_iNumberStatus == NUMBER_PORZERO)) {
				// Un numero entero
				m_jPor.setText("x" + Character.toString(cTrans));
				m_iNumberStatus = NUMBER_PORINT;
				m_iNumberStatusPor = NUMBERVALID;
			} else if ((cTrans == '0' || cTrans == '1' || cTrans == '2'
					|| cTrans == '3' || cTrans == '4' || cTrans == '5'
					|| cTrans == '6' || cTrans == '7' || cTrans == '8' || cTrans == '9')
					&& (m_iNumberStatus == NUMBER_PORINT)) {
				// Un numero entero
				m_jPor.setText(m_jPor.getText() + cTrans);
	
			} else if (cTrans == '.' && m_iNumberStatus == NUMBER_PORZERO) {
				m_jPor.setText("x0.");
				m_iNumberStatus = NUMBER_PORZERODEC;
			} else if (cTrans == '.' && m_iNumberStatus == NUMBER_PORINT) {
				m_jPor.setText(m_jPor.getText() + ".");
				m_iNumberStatus = NUMBER_PORDEC;
	
			} else if ((cTrans == '0')
					&& (m_iNumberStatus == NUMBER_PORZERODEC || m_iNumberStatus == NUMBER_PORDEC)) {
				// Un numero decimal
				m_jPor.setText(m_jPor.getText() + cTrans);
			} else if ((cTrans == '1' || cTrans == '2' || cTrans == '3'
					|| cTrans == '4' || cTrans == '5' || cTrans == '6'
					|| cTrans == '7' || cTrans == '8' || cTrans == '9')
					&& (m_iNumberStatus == NUMBER_PORZERODEC || m_iNumberStatus == NUMBER_PORDEC)) {
				// Un numero decimal
				m_jPor.setText(m_jPor.getText() + cTrans);
				m_iNumberStatus = NUMBER_PORDEC;
				m_iNumberStatusPor = NUMBERVALID;
	
			} else if (cTrans == '\u00a7'
					&& m_iNumberStatusInput == NUMBERVALID
					&& m_iNumberStatusPor == NUMBERZERO) {
				// Scale button pressed and a number typed as a price
				if (m_App.getDeviceScale().existsScale()
						&& security.hasPermissionByName( "sales.EditLines")) {
					try {
						Double value = m_App.getDeviceScale().readWeight();
						if (value != null) {
							Product product = getInputProduct();
							addTicketLine(product, value.doubleValue(),
									product.getPriceSell());
						}
					} catch (ScaleException e) {
						Toolkit.getDefaultToolkit().beep();
						new MessageInf(MessageInf.SGN_WARNING,
								AppLocal.getIntString("message.noweight"), e)
								.show(this);
						stateToZero();
					}
				} else {
					// No existe la balanza;
					Toolkit.getDefaultToolkit().beep();
				}
			} else if (cTrans == '\u00a7' && m_iNumberStatusInput == NUMBERZERO
					&& m_iNumberStatusPor == NUMBERZERO) {
				// Scale button pressed and no number typed.
				int i = m_ticketlines.getSelectedIndex();
				if (i < 0) {
					Toolkit.getDefaultToolkit().beep();
				} else if (m_App.getDeviceScale().existsScale()) {
					try {
						Double value = m_App.getDeviceScale().readWeight();
						if (value != null) {
							TicketLine newline =m_oTicket.getLine(i).copyTicketLine();
							newline.setMultiply(value.doubleValue());
	
							TicketLineHelper.setPrice(newline, Math
									.abs(TicketLineHelper.getPrice(newline)));
							paintTicketLine(i, newline);
						}
					} catch (ScaleException e) {
						// Error de pesada.
						Toolkit.getDefaultToolkit().beep();
						new MessageInf(MessageInf.SGN_WARNING,
								AppLocal.getIntString("message.noweight"), e)
								.show(this);
						stateToZero();
					}
				} else {
					// No existe la balanza;
					Toolkit.getDefaultToolkit().beep();
				}
	
				// Add one product more to the selected line
			} else if (cTrans == '+' && m_iNumberStatusInput == NUMBERZERO
					&& m_iNumberStatusPor == NUMBERZERO) {
				
				int i = m_ticketlines.getSelectedIndex();
				if (i < 0) {
					Toolkit.getDefaultToolkit().beep();
				} else {
					TicketLine newline = m_oTicket.getLine(i).copyTicketLine();
					// If it's a refund + button means one unit less
					if (m_oTicket.getTicketType() == Ticket.RECEIPT_REFUND) {
						newline.setMultiply(newline.getMultiply() - 1.0);
						paintTicketLine(i, newline);
					} else {
						// add one unit to the selected line
						newline.setMultiply(newline.getMultiply() + 1.0);
						try {
							TicketUtil.checkTicketLineProductPrefPrice(dlSales, m_oTicket, newline,m_App.getDefineLocation());
						} catch (BasicException e) {
							new MessageInf(MessageInf.SGN_WARNING,
									AppLocal.getIntString("message.checkPrefPriceError"), e)
									.show(this);
						}
						paintTicketLine(i, newline);
					}
				}
	
				// Delete one product of the selected line
			} else if (cTrans == '-' && m_iNumberStatusInput == NUMBERZERO
					&& m_iNumberStatusPor == NUMBERZERO) {
				if (m_ticketlines.getRowCount() == 0) {
					m_ticketsbag.showPrevTicket();
					return;
				} else if (security.hasPermissionByName("sales.EditLines")) {

					int i = m_ticketlines.getSelectedIndex();
					if (i < 0) {
						Toolkit.getDefaultToolkit().beep();
					} else {
						TicketLine newline = m_oTicket.getLine(i)
								.copyTicketLine();
						// If it's a refund - button means one unit more
						if (m_oTicket.getTicketType() == Ticket.RECEIPT_REFUND) {
							newline.setMultiply(newline.getMultiply() + 1.0);
							if (newline.getMultiply() >= 0) {
								removeTicketLine(i);
							} else {
								paintTicketLine(i, newline);
							}
						} else {
							// substract one unit to the selected line
							newline.setMultiply(newline.getMultiply() - 1.0);
							if (newline.getMultiply() <= 0.0) {
								removeTicketLine(i); // elimino la linea
							} else {
								try {
									TicketUtil.checkTicketLineProductPrefPrice(
											dlSales, m_oTicket, newline,
											m_App.getDefineLocation());
								} catch (BasicException e) {
									new MessageInf(
											MessageInf.SGN_WARNING,
											AppLocal.getIntString("message.checkPrefPriceError"),
											e).show(this);
								}
								paintTicketLine(i, newline);
							}
						}
					}
				}
				// Set n products to the selected line
			} else if (cTrans == '+' && m_iNumberStatusInput == NUMBERZERO
					&& m_iNumberStatusPor == NUMBERVALID) {
				int i = m_ticketlines.getSelectedIndex();
				if (i < 0) {
					Toolkit.getDefaultToolkit().beep();
				} else {
					double dPor = getPorValue();
					TicketLine newline = m_oTicket.getLine(i).copyTicketLine();
					if (m_oTicket.getTicketType() == Ticket.RECEIPT_REFUND) {
						newline.setMultiply(-dPor);
	
						TicketLineHelper.setPrice(newline,
								Math.abs(TicketLineHelper.getPrice(newline)));
						paintTicketLine(i, newline);
					} else {
						newline.setMultiply(dPor);
	
						TicketLineHelper.setPrice(newline,
								Math.abs(TicketLineHelper.getPrice(newline)));
						try {
							TicketUtil.checkTicketLineProductPrefPrice(dlSales, m_oTicket, newline,m_App.getDefineLocation());
						} catch (BasicException e) {
							new MessageInf(MessageInf.SGN_WARNING,
									AppLocal.getIntString("message.checkPrefPriceError"), e)
									.show(this);
						}
						paintTicketLine(i, newline);
					}
				}
	
				// Set n negative products to the selected line
			} else if (cTrans == '-'
					&& m_iNumberStatusInput == NUMBERZERO
					&& m_iNumberStatusPor == NUMBERVALID
					&& security.hasPermissionByName("sales.EditLines")) {
	
				int i = m_ticketlines.getSelectedIndex();
				if (i < 0) {
					Toolkit.getDefaultToolkit().beep();
				} else {
					double dPor = getPorValue();
					TicketLine newline = m_oTicket.getLine(i).copyTicketLine();
					if (m_oTicket.getTicketType() == Ticket.RECEIPT_NORMAL) {
						newline.setMultiply(dPor);
	
						TicketLineHelper.setPrice(newline,
								-Math.abs(TicketLineHelper.getPrice(newline)));
						try {
							TicketUtil.checkTicketLineProductPrefPrice(dlSales, m_oTicket, newline,m_App.getDefineLocation());
						} catch (BasicException e) {
							new MessageInf(MessageInf.SGN_WARNING,
									AppLocal.getIntString("message.checkPrefPriceError"), e)
									.show(this);
						}
						paintTicketLine(i, newline);
					}
				}
	
				// Anadimos 1 producto
			} else if (cTrans == '+'
					&& m_iNumberStatusInput == NUMBERVALID
					&& m_iNumberStatusPor == NUMBERZERO
					&& security.hasPermissionByName("sales.EditLines")) {
				Product product = getInputProduct();
				addTicketLine(product, 1.0, product.getPriceSell());
	
				// Anadimos 1 producto con precio negativo
			} else if (cTrans == '-'
					&& m_iNumberStatusInput == NUMBERVALID
					&& m_iNumberStatusPor == NUMBERZERO
					&& security.hasPermissionByName("sales.EditLines")) {
				Product product = getInputProduct();
				addTicketLine(product, 1.0, -product.getPriceSell());
	
				// Anadimos n productos
			} else if (cTrans == '+'
					&& m_iNumberStatusInput == NUMBERVALID
					&& m_iNumberStatusPor == NUMBERVALID
					&& security.hasPermissionByName("sales.EditLines")) {
				Product product = getInputProduct();
				addTicketLine(product, getPorValue(), product.getPriceSell());
	
				// Anadimos n productos con precio negativo ?
			} else if (cTrans == '-'
					&& m_iNumberStatusInput == NUMBERVALID
					&& m_iNumberStatusPor == NUMBERVALID
					&& security.hasPermissionByName("sales.EditLines")) {
				Product product = getInputProduct();
				addTicketLine(product, getPorValue(), -product.getPriceSell());
	
				// Totals() Igual;
			} else if (cTrans == ' ' || cTrans == '=') {
				if (m_oTicket.getLinesCount() > 0) {
	
					if (closeTicket(m_oTicket, m_oTicketExt)) {
						// Ends edition of current receipt
						m_ticketsbag.flushTicket();
					} else {
						// repaint current ticket
						refreshTicket();
					}
				} else {
					Toolkit.getDefaultToolkit().beep();
				}
			}
		}
	}

	private void quickSaleByKeyStoke(char cTrans) {
		Product findProduct=null;
		try {
			findProduct = dlSales.findProductByKeyStoke(String.valueOf(cTrans));
		} catch (BasicException e) {
			Toolkit.getDefaultToolkit().beep(); 
            stateToZero();
            new MessageInf(MessageInf.SGN_WARNING, AppLocal.getIntString("message.noproduct")).show(this);
		}
		if(findProduct!=null)
		    incProduct(findProduct);
	}


	private boolean closeTicket(Ticket ticket, Object ticketext) {
		boolean resultok = false;
		cashChanged = "0.0";
		cashPaid=null;
		double cashPayed=0.0;
		ticket.setHostName(m_App.getProperties().getHost());
		if (security.hasPermissionByName("sales.Total")) {
	        
			try {
				// reset the payment info
				taxeslogic.calculateTaxes(ticket);
				if (TicketHelper.getTotal(ticket) >= 0.0) {
					ticket.resetPayments(); // Only reset if is sale
				}
	
				ticket.setTotalTax(TicketHelper.getTax(ticket));
				ticket.setTotalPrice(TicketHelper.getTotal(ticket));
				ticket.setTotalConsultCost(TicketHelper.getTotalConsultCost(ticket));
				ticket.setTotalScore(TicketHelper.getTotalScore(ticket));
	
				if (executeEvent(ticket, ticketext, "ticket.total") == null) {
	
					// Muestro el total
					printTicket("Printer.TicketTotal", ticket, ticketext);
	
					// Select the Payments information
					JPaymentSelect paymentdialog = ticket
							.getTicketType() == Ticket.RECEIPT_NORMAL ? paymentdialogreceipt
							: paymentdialogrefund;
					// paymentdialog.setPrintSelected("true".equals(m_jbtnconfig.getProperty("printselected",
					// "true")));
	
					paymentdialog.setTransactionID(TicketHelper
							.getTransactionID(ticket));
	
					if (paymentdialog.showDialog(ticket.getTotalPrice(),
							ticket.getCustomer())) {
	
						// assign the payments selected and calculate taxes.
						ticket.setPayments(paymentdialog.getSelectedPayments());
	
						// Asigno los valores definitivos del ticket...
						ticket.setUser(m_App.getAppUserView().getUser()
								.getUserInfo()); // El usuario que lo cobra
						ticket.setActiveCash(m_App.getUserCashIndex());
						ticket.setDate(new Date()); // Le pongo la fecha de
													// cobro
	
						if (executeEvent(ticket, ticketext, "ticket.save") == null) {
							// Save the receipt and assign a receipt number
							try {
								dlSales.saveTicket(ticket,
										m_App.getInventoryLocation());
							} catch (BasicException eData) {
								MessageInf msg = new MessageInf(
										MessageInf.SGN_NOTICE,
										AppLocal.getIntString("message.nosaveticket"),
										eData);
								msg.show(this);
								return false;
							}
	
							executeEvent(
									ticket,
									ticketext,
									"ticket.close",
									new ScriptArg("print", paymentdialog
											.isPrintSelected()));
	
							// Print receipt.
							if (paymentdialog.isPrintSelected())
								printTicket("Printer.Ticket2", ticket,
										ticketext);
							resultok = true;
						}
	
						for (PaymentInfo p : ticket.getPayments()) {
							if (p.getName().equalsIgnoreCase("cash")) {
								PaymentInfoCash pInfoCash=(PaymentInfoCash)p;
								cashPaid= PaymentInfoHelper.printPaid((PaymentInfoCash) p);
								if((pInfoCash.getPaid()-pInfoCash.getTotal())!=0.0){
								   cashChanged = PaymentInfoHelper
										.printChange((PaymentInfoCash) p);
								   break;
								}
							}
						}
						
					}
				}
			} catch (TaxesException e) {
				MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
						AppLocal.getIntString("message.cannotcalculatetaxes"));
				msg.show(this);
				resultok = false;
			}
	        if(!resultok){
			   // reset the payment info
			   m_oTicket.resetTaxes();
			   m_oTicket.resetPayments();
	        }
		}
	
		// cancelled the ticket.total script
		// or canceled the payment dialog
		// or canceled the ticket.close script
		return resultok;
	}

	public void printTicket(String sresourcename, Ticket ticket, Object ticketext) {
	
		String sresource = dlSystem.getResourceAsXML(sresourcename);
		if (sresource == null) {
			MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
					AppLocal.getIntString("message.cannotprintticket"));
			msg.show(AbstractJPanelTicket.this);
		} else {
			try {
				ScriptEngine script = ScriptFactory
						.getScriptEngine(ScriptFactory.VELOCITY);
				script.put("taxes", taxcollection);
				script.put("taxeslogic", taxeslogic);
				script.put("ticket", new TicketWarp(ticket));
				script.put("place", ticketext);
				script.put("warehouse", m_App.getsWareHouse());
				m_TTP.printTicket(script.eval(sresource).toString());
			} catch (ScriptException e) {
				MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
						AppLocal.getIntString("message.cannotprintticket"), e);
				msg.show(AbstractJPanelTicket.this);
			} catch (TicketPrinterException e) {
				MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
						AppLocal.getIntString("message.cannotprintticket"), e);
				msg.show(AbstractJPanelTicket.this);
			}
		}
	}

	protected void printReport(String resourcefile, Ticket ticket, Object ticketext) {
	
		try {
	
			JasperReport jr;
	
			InputStream in = getClass().getResourceAsStream(
					resourcefile + ".ser");
			if (in == null) {
				// read and compile the report
				JasperDesign jd = JRXmlLoader.load(getClass()
						.getResourceAsStream(resourcefile + ".jrxml"));
				jr = JasperCompileManager.compileReport(jd);
			} else {
				// read the compiled reporte
				ObjectInputStream oin = new ObjectInputStream(in);
				jr = (JasperReport) oin.readObject();
				oin.close();
			}
	
			// Construyo el mapa de los parametros.
			Map reportparams = new HashMap();
			// reportparams.put("ARG", params);
			try {
				reportparams.put("REPORT_RESOURCE_BUNDLE",
						ResourceBundle.getBundle(resourcefile + ".properties"));
			} catch (MissingResourceException e) {
			}
			reportparams.put("TAXESLOGIC", taxeslogic);
	
			Map reportfields = new HashMap();
			reportfields.put("TICKET", new TicketWarp(ticket));
			reportfields.put("PLACE", ticketext);
			reportfields.put("WAREHOUSE", m_App.getsWareHouse());
	
			JasperPrint jp = JasperFillManager.fillReport(jr, reportparams,
					new JRMapArrayDataSource(new Object[] { reportfields }));
	
			PrintService service = ReportUtils.getPrintService(m_App
					.getProperties().getProperty("machine.printername"));
	
			JRPrinterAWT300
					.printPages(jp, 0, jp.getPages().size() - 1, service);
	
		} catch (Exception e) {
			MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
					AppLocal.getIntString("message.cannotloadreport"), e);
			msg.show(this);
		}
	}

	private void visorTicketLine(TicketLine oLine) {
		if (oLine == null) {
			m_App.getDeviceTicket().getDeviceDisplay().clearVisor();
		} else {
			try {
				ScriptEngine script = ScriptFactory
						.getScriptEngine(ScriptFactory.VELOCITY);
				script.put("ticketline", new TicketLineWarp(oLine));
				m_TTP.printTicket(script.eval(
						dlSystem.getResourceAsXML("Printer.TicketLine"))
						.toString());
			} catch (ScriptException e) {
				MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
						AppLocal.getIntString("message.cannotprintline"), e);
				msg.show(AbstractJPanelTicket.this);
			} catch (TicketPrinterException e) {
				MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
						AppLocal.getIntString("message.cannotprintline"), e);
				msg.show(AbstractJPanelTicket.this);
			}
		}
	}

	private Object evalScript(ScriptObject scr, String resource, ScriptArg... args) {
	
		// resource here is guaratied to be not null
		try {
			scr.setSelectedIndex(m_ticketlines.getSelectedIndex());
			return scr.evalScript(dlSystem.getResourceAsXML(resource), args);
		} catch (ScriptException e) {
			MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
					AppLocal.getIntString("message.cannotexecute"), e);
			msg.show(this);
			return msg;
		}
	}

	public void evalScriptAndRefresh(String resource, ScriptArg... args) {
	
		if (resource == null) {
			MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
					AppLocal.getIntString("message.cannotexecute"));
			msg.show(this);
		} else {
			ScriptObject scr = new ScriptObject(m_oTicket, m_oTicketExt);
			scr.setSelectedIndex(m_ticketlines.getSelectedIndex());
			evalScript(scr, resource, args);
			refreshTicket();
			setSelectedIndex(scr.getSelectedIndex());
		}
	}

	public void print(String resource) {
		printTicket(resource, m_oTicket, m_oTicketExt);
	}

	private Object executeEventAndRefresh(String eventkey, ScriptArg... args) {
	
		String resource = m_jbtnconfig.getEvent(eventkey);
		if (resource == null) {
			return null;
		} else {
			ScriptObject scr = new ScriptObject(m_oTicket, m_oTicketExt);
			scr.setSelectedIndex(m_ticketlines.getSelectedIndex());
			Object result = evalScript(scr, resource, args);
			refreshTicket();
			setSelectedIndex(scr.getSelectedIndex());
			return result;
		}
	}

	private Object executeEvent(Ticket ticket, Object ticketext, String eventkey,
			ScriptArg... args) {
			
				String resource = m_jbtnconfig.getEvent(eventkey);
				if (resource == null) {
					return null;
				} else {
					ScriptObject scr = new ScriptObject(ticket, ticketext);
					return evalScript(scr, resource, args);
				}
			}

	public String getResourceAsXML(String sresourcename) {
		return dlSystem.getResourceAsXML(sresourcename);
	}

	public BufferedImage getResourceAsImage(String sresourcename) {
		return DataLogicSystemHelper.getResourceAsImage(dlSystem,sresourcename);
	}

	private void setSelectedIndex(int i) {
		if (i >= 0 && i < m_oTicket.getLinesCount()) {
			m_ticketlines.setSelectedIndex(i);
		} else if (m_oTicket.getLinesCount() > 0) {
			m_ticketlines.setSelectedIndex(m_oTicket.getLinesCount() - 1);
		}
	}

	protected javax.swing.JButton jEditAttributes;
	private JProductFinder productFinder;

	protected void m_jbtnScaleActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_m_jbtnScaleActionPerformed
		stateTransition('\u00a7');
	
	}// GEN-LAST:event_m_jbtnScaleActionPerformed

	protected void m_jEditLineActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_m_jEditLineActionPerformed
	    if(!isEditAble)
	    	return;
		int i = m_ticketlines.getSelectedIndex();
		if (i < 0) {
			Toolkit.getDefaultToolkit().beep(); // no line selected
		} else {
			try {
				TicketLine selectedline = m_oTicket.getLine(i);
				if (selectedline != null && selectedline.isServiceTicketLine()) {
					JServingsEditorDialog servingsEditorDialog = JServingsEditorDialog
							.getDialog(this);
					servingsEditorDialog.init(dlSales,
							selectedline.getServings(), true);
					servingsEditorDialog.setVisible(true);
					if (servingsEditorDialog.isOK()) {
						selectedline.setServings(servingsEditorDialog
								.getServings());
						paintTicketLine(i, selectedline);
					}
				} else {
					TicketLine oldline=m_oTicket.getLine(i);
					double oldMultipy=oldline.getMultiply();
					TicketLine newline = JProductLineEdit.showMessage(
							this, m_App, oldline, dlSales, dlSystem,security);
					if (newline != null&&newline.getProductID()!=null) {
						if(newline.getMultiply()!=oldMultipy){
							if(m_oTicket.getTicketType()==Ticket.RECEIPT_NORMAL&&isCheckProductLocation&&!dlSales.isProductStoreEnough(m_App.getInventoryLocation(), newline.getProductID(),newline.getMultiply())){
								new MessageInf(MessageInf.SGN_WARNING,AppLocal.getIntString("message.productNoStoreEnough")).show(this);
								return;
							}
							TicketUtil.checkTicketLineProductPrefPrice(dlSales, m_oTicket, newline,m_App.getDefineLocation());
						}
						// line has been modified
						paintTicketLine(i, newline);
					}
				}
			} catch (BasicException e) {
				new MessageInf(e).show(this);
			}
		}
	
	}// GEN-LAST:event_m_jEditLineActionPerformed

	protected void m_jEnterActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_m_jEnterActionPerformed
		stateTransition('\n');
	
	}// GEN-LAST:event_m_jEnterActionPerformed

	protected void m_jNumberKeysKeyPerformed(com.openbravo.beans.JNumberEvent evt) {// GEN-FIRST:event_m_jNumberKeysKeyPerformed
		stateTransition(evt.getKey());
	
	}// GEN-LAST:event_m_jNumberKeysKeyPerformed

	protected void m_jKeyFactoryKeyTyped(java.awt.event.KeyEvent evt) {// GEN-FIRST:event_m_jKeyFactoryKeyTyped
		m_jKeyFactory.setText(null);
		stateTransition(evt.getKeyChar());
	
	}// GEN-LAST:event_m_jKeyFactoryKeyTyped

	protected void m_jDeleteActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_m_jDeleteActionPerformed
		if(!isEditAble)
	    	return;
		int i = m_ticketlines.getSelectedIndex();
		if (i < 0) {
			Toolkit.getDefaultToolkit().beep(); // No hay ninguna seleccionada
		} else {
			removeTicketLine(i); // elimino la linea
		}
	
	}// GEN-LAST:event_m_jDeleteActionPerformed

	protected void m_jUpActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_m_jUpActionPerformed
	
		m_ticketlines.selectionUp();
	
	}// GEN-LAST:event_m_jUpActionPerformed

	protected void m_jDownActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_m_jDownActionPerformed
	
		m_ticketlines.selectionDown();
	
	}// GEN-LAST:event_m_jDownActionPerformed

	protected void m_jListActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_m_jListActionPerformed
		if(!isEditAble)
	    	return;
		Product prod = JProductFinder.showMessage(
				AbstractJPanelTicket.this, dlSales);
		if (prod != null) {
			buttonTransition(prod);
		}
	
	}// GEN-LAST:event_m_jListActionPerformed

	protected void btnCustomerActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_btnCustomerActionPerformed
		if(!isEditAble)
	    	return;
		JCustomerFinder finder = JCustomerFinder.getCustomerFinder(this,
				this.dlSales);
		finder.search(m_oTicket.getCustomer());
		finder.setVisible(true);
	
		try {
			CustomerInfo custInfo = finder.getSelectedCustomer();
			Customer customer = null;
			if (custInfo != null) {
				customer = (Customer) dlSales.findByStringId(Customer.class, finder
						.getSelectedCustomer().getId());
			}
			TicketUtil.changeCustomer(dlSales, m_oTicket, customer,priceGroup);
			m_oTicket.setCustomer(customer);
		} catch (BasicException e) {
			MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
					AppLocal.getIntString("message.cannotfindcustomer"), e);
			msg.show(this);
		}
		refreshTicket();
	
	}// GEN-LAST:event_btnCustomerActionPerformed

	protected void addNewCustomer() {
		if(!isEditAble)
	    	return;
		if (!RoleUtil.hasPermission(AbstractJPanelTicket.this, (AppUser) m_App
				.getAppUserView().getUser(), dlSystem,
				RoleUtil.Permission_ADD_CUSTOMER))
			return;
	
		if (customerCreateDialog == null)
			customerCreateDialog =JEditorWarpDialog.getInstance(this).init( dlSales,
					new CustomersEditor(dlSales, new DirtyManager()));
	
		try {
			customerCreateDialog.activate();
		} catch (BasicException e) {
			JMessageDialog.showMessage(
					this,
					new MessageInf(MessageInf.SGN_WARNING, AppLocal
							.getIntString("message.notactive"), e));
			return;
		}
		customerCreateDialog.writeValueInsert(null);
		if (customerCreateDialog.getRetObj() != null) {
			try {
				TicketUtil.changeCustomer(dlSales, m_oTicket,
						(Customer) customerCreateDialog.getRetObj(),priceGroup);
				m_oTicket.setCustomer((Customer) customerCreateDialog.getRetObj());
			} catch (BasicException e) {
				new MessageInf(e).show(this);
			}
			refreshTicket();
		}
	}

	protected void btnSplitActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_btnSplitActionPerformed
		if(!isEditAble)
	    	return;
		if (m_oTicket.getLinesCount() > 0) {
			ReceiptSplit splitdialog = ReceiptSplit.getDialog(
					this, dlSystem.getResourceAsXML("Ticket.Line"), dlSales,
					dlCustomers, taxeslogic);
			Ticket ticket1 = m_oTicket.copyTicket();
			Ticket ticket2 = new Ticket();
			ticket2.setCustomer(m_oTicket.getCustomer());
	
			if (splitdialog.showDialog(ticket1, ticket2, m_oTicketExt)) {
				if (closeTicket(ticket2, m_oTicketExt)) { // already checked
															// that number of
															// lines > 0
					if (printManager != null) {
						try {
							printManager.fireTicketCreated(new TicketEvent(
									ticket2));
							printManager.fireTicketFlushed(new TicketEvent(
									ticket2));
						} catch (TicketPrinterException e) {
							e.printStackTrace();
						} catch (ScriptException e) {
							e.printStackTrace();
						}
					}
					setActiveTicket(ticket1, m_oTicketExt,true);// set result ticket
					if (printManager != null) {
						try {
							printManager.fireTicketCreated(new TicketEvent(ticket1));
						} catch (TicketPrinterException e) {
							e.printStackTrace();
						} catch (ScriptException e) {
							e.printStackTrace();
						}
					}
				}
			}
		}
	
	}// GEN-LAST:event_btnSplitActionPerformed

	protected void jEditAttributesActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_jEditAttributesActionPerformed
		if(!isEditAble)
	    	return;
		int i = m_ticketlines.getSelectedIndex();
		if (i < 0) {
			Toolkit.getDefaultToolkit().beep(); // no line selected
		} else {
			try {
				TicketLine line = m_oTicket.getLine(i);
				JProductAttEdit attedit = JProductAttEdit
						.getAttributesEditor(this,this.dlSales);
				attedit.editAttributes(line.getProductAttSetId(),
						line.getProductAttSetInstId(),line.getProductid());
				attedit.setVisible(true);
				if (attedit.isOK()) {
					// The user pressed OK
					line.setProductAttSetInstId(attedit.getAttributeSetInstance().getId());
					line.setProductAttSetInstDesc(attedit.getAttributeSetInstance().getDescription());
					line.setAttrPrice(attedit.getAttributeSetInstance().getDiffPrice());
					line.setAttrPriceCost(attedit.getAttributeSetInstance().getDiffPriceCost());
					paintTicketLine(i, line);
				}
			} catch (BasicException ex) {
				MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
						AppLocal.getIntString("message.cannotfindattributes"),
						ex);
				msg.show(this);
			}
		}
	
	}// GEN-LAST:event_jEditAttributesActionPerformed

	protected void m_jEditLineAttrib() {
		if(!isEditAble)
	    	return;
		int i = m_ticketlines.getSelectedIndex();
		if (i < 0) {
			Toolkit.getDefaultToolkit().beep(); // no line selected
		} else {
			try {
				TicketLine line = m_oTicket.getLine(i);
				JTicketLinePropEdit propEdit = JTicketLinePropEdit.getPropEdit(
						this,
						line.getProperty(TicketLine.TICKETlINE_EXTPROP, ""));
				propEdit.setVisible(true);
				if (propEdit.isOK()) {
					line.setProperty(TicketLine.TICKETlINE_EXTPROP,
							propEdit.getRetProps());
					paintTicketLine(i, line);
				}
			} catch (BasicException ex) {
				MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
						AppLocal.getIntString("message.cannotfindattributes"),
						ex);
				msg.show(this);
			}
		}
	}

	public void changeTicketRate() {
		if(!isEditAble)
	    	return;
		if (!RoleUtil.hasPermission(AbstractJPanelTicket.this, (AppUser) m_App
				.getAppUserView().getUser(), dlSystem,
				RoleUtil.Permission_CHANGE_TICKET_RATE))
			return;
		JChangeRateDialog rantDialog = JChangeRateDialog.getDialog(this,
				m_oTicket.getM_dPriceRate());
		rantDialog.setVisible(true);
		if (rantDialog.isOk()) {
			Double changedRant = rantDialog.getChangeRate();
			TicketUtil.changeRate(m_oTicket, changedRant);
		}
		refreshTicket();
	}

	protected void changeTicketType() {
		if(!isEditAble)
	    	return;
		if (m_oTicket.getLinesCount() > 0) {
			MessageInf msg = new MessageInf(MessageInf.SGN_WARNING,
					AppLocal.getIntString("message.theTickeMustEmpty"));
			msg.show(this);
			return;
		}
	
		if (!RoleUtil.hasPermission(AbstractJPanelTicket.this, (AppUser) m_App
				.getAppUserView().getUser(), dlSystem,
				RoleUtil.Permission_CHANGE_TICKET_TYPE))
			return;
	
		if (Ticket.RECEIPT_NORMAL == m_oTicket.getTicketType()) {
			m_oTicket.setTicketType(Ticket.RECEIPT_REFUND);
		} else if (Ticket.RECEIPT_REFUND == m_oTicket.getTicketType()) {
			m_oTicket.setTicketType(Ticket.RECEIPT_NORMAL);
		}
		printPartialTotals();
	}


	protected void addServings() {
		if(!isEditAble)
	    	return;
		try {
			JServingsEditorDialog servingsEditorDialog = JServingsEditorDialog
					.getDialog(this);
			servingsEditorDialog.init(dlSales, null, true);
			servingsEditorDialog.setVisible(true);
			if (servingsEditorDialog.isOK()) {
				Serving retServings = servingsEditorDialog.getServings();
				if (retServings != null) {
					String tcid = ((TaxCategory) taxcategoriesmodel
							.getSelectedItem()).getID();
					Tax tax = taxeslogic.getTaxInfo(tcid,
							m_oTicket.getCustomer());
					addTicketLine(new TicketLine(retServings, tax,
							m_oTicket.getM_dPriceRate()));
				}
			}
		} catch (BasicException ex) {
			JMessageDialog.showMessage(
					this,
					new MessageInf(MessageInf.SGN_WARNING, AppLocal
							.getIntString("message.notactive"), ex));
			return;
		}
	}

	JPhysicalBondDialog jPhysicalBondDialog;
	protected void physicalBondTicket(){
		if(jPhysicalBondDialog==null)
			jPhysicalBondDialog=JPhysicalBondDialog.getDialog(this, dlSales,m_App.getInventoryLocation());
		jPhysicalBondDialog.setVisible(true);
	}
	
	
	protected void showProductDetail() {
		JProductDetail.getInstance(this, dlSales, dlSystem, m_App).setVisible(true);
	}
	
	public class ScriptObject {
		private Ticket ticket;
		private Object ticketext;
		private int selectedindex;

		private ScriptObject(Ticket ticket, Object ticketext) {
			this.ticket = ticket;
			this.ticketext = ticketext;
		}

		public double getInputValue() {
			if (m_iNumberStatusInput == NUMBERVALID
					&& m_iNumberStatusPor == NUMBERZERO) {
				return AbstractJPanelTicket.this.getInputValue();
			} else {
				return 0.0;
			}
		}

		public int getSelectedIndex() {
			return selectedindex;
		}

		public void setSelectedIndex(int i) {
			selectedindex = i;
		}

		public void printReport(String resourcefile) {
			AbstractJPanelTicket.this.printReport(resourcefile, ticket,
					ticketext);
		}

		public void printTicket(String sresourcename) {
			AbstractJPanelTicket.this.printTicket(sresourcename, ticket,
					ticketext);
		}

		public Object evalScript(String code, ScriptArg... args)
				throws ScriptException {

			ScriptEngine script = ScriptFactory
					.getScriptEngine(ScriptFactory.BEANSHELL);
			script.put("ticket", ticket);
			script.put("place", ticketext);
			script.put("taxes", taxcollection);
			script.put("taxeslogic", taxeslogic);
			script.put("user", m_App.getAppUserView().getUser());
			script.put("sales", this);

			// more arguments
			for (ScriptArg arg : args) {
				script.put(arg.getKey(), arg.getValue());
			}

			return script.eval(code);
		}
	}
	
	
	 public JProductFinder getProductFinder() {
	        if(productFinder==null)
	            productFinder=JProductFinder.getInstance(this, dlSales,JProductFinder.PRODUCT_ALL);
	        return productFinder;
	 }

	public boolean isEditAble() {
		return isEditAble;	
	}    
	
	protected javax.swing.JTextField m_jKeyFactory;
	protected javax.swing.JLabel m_jTicketId;
	protected javax.swing.JLabel m_jPor;
	protected javax.swing.JLabel m_jPrice;
	protected javax.swing.JToggleButton m_jaddtax;

	@Override
	public String getModelName() {
		return POS_UI_Swing_Model.MODEL_NAME;
	}

	protected POS_UI_Swing_Model mode;
	@Override
	public void setModel(POS_UI_Swing_Model mode) {
		dlSystem = mode.getDLSystem();
		dlSales = mode.getDLSales();
		dlCustomers = mode.getDLCustomer();
		dlReceipts=mode.getDLReceipts();
		this.mode=mode;
		security=mode.getModelSecurityManager();
	}


	public I_DataLogicSystem getDlSystem() {
		return dlSystem;
	}

	public I_DataLogicSales getDlSales() {
		return dlSales;
	}

	public I_DataLogicCustomers getDlCustomers() {
		return dlCustomers;
	}

	public I_DataLogicReceipts getDlReceipts() {
		return dlReceipts;
	}


	@Override
	public I_SecurityManager getSecurityManager() {
		return security;
	}
	
	
}